/*******************************************************************************
  * 文件：Hardware_Flash.c
  * 作者：djy
  * 版本：v1.0.0
  * 日期：2020-11-27
  * 说明：Flash外设
*******************************************************************************/
#include "Hardware_Flash.h"
#include "lib_iap.h"
#include "Hardware_WDT.h"
#include "ComFun.h"

/*******************************************************************************
  * 函数名：Hardware_FlashLock
  * 功  能：Flash上锁
  * 参  数：无
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void Hardware_FlashLock(void)
{
    IAP_FLASH_Lock();
}

/*******************************************************************************
  * 函数名：Hardware_FlashUnlock
  * 功  能：Flash解锁
  * 参  数：无
  * 返回值：无
  * 说  明：无
*******************************************************************************/
void Hardware_FlashUnlock(void)
{
    IAP_FLASH_Unlock();
}

/*******************************************************************************
  * 函数名：Hardware_FlashErase
  * 功  能：Flash擦除页
  * 参  数：U32 u32PageAddr:页地址，必须为页大小的整数倍
  * 	    U16 u16PageNums：擦除的页数
  * 返回值：TRUE:成功  		FALSE:失败
  * 说  明：无
*******************************************************************************/
Bool Hardware_FlashErase(U32 u32PageAddr,U16 u16PageNums)
{
    if((u32PageAddr&(U32)ES8H0183_FLASH_PAGE_MASK) 
    	|| (u16PageNums > ES8H0183_FLASH_PAGE_NUMS) 
    	|| (u16PageNums == 0))
    {
        // 地址不对齐或擦除页数不正确
        return FALSE;
    }

    // 解锁Flash    
	Hardware_FlashUnlock();
    
    // 按页擦除
	while(u16PageNums > 0)
	{
	    // 复位看门狗
	    Hardware_RestartWDT();
	    
        // 擦除Flash页
	    if(ERROR == IAP_Code_PageErase(u32PageAddr,~u32PageAddr))
	    {
	        // Flash上锁
	        Hardware_FlashLock();
            
            // 擦除失败
	        return 0;
	    }
        
	    // 页数减1
	    u16PageNums--;
        
	    // 指向下一页
	    u32PageAddr += ES8H0183_FLASH_PAGE_SIZE;
	}
    
	//Flash上锁
	Hardware_FlashLock();
	
    // 擦除成功
    return TRUE;
}

/*******************************************************************************
  * 函数名：Hardware_FlashRead
  * 功  能：Flash读取数据
  * 参  数：void *Data：读取数据缓存地址
  *		   U32 u32ReadAddr：Flash读取地址
  *		   U32 u32ReadByteLen：读取字节长度
  * 返回值：TRUE:成功  		FALSE:失败
  * 说  明：无
*******************************************************************************/
Bool Hardware_FlashRead(void *Data,U32 u32ReadAddr,U32 u32ReadByteLen)
{
	U8 *pu8Buffer = NULL;
	
	pu8Buffer = (U8 *)Data;

    if((u32ReadAddr > ES8H0183_FLASH_START_ADDR + ES8H0183_FLASH_SIZE) 
    	|| (u32ReadByteLen <= 0)
    	|| (u32ReadByteLen > ES8H0183_FLASH_SIZE))
    {
    	// 读取地址或读取数据长度非法，返回失败
    	return FALSE;
    }

    // 直接寻址
	while (u32ReadByteLen--)
	{
		*(pu8Buffer++) = *(__IO U8 *)(u32ReadAddr++);
	}

    // 返回成功
    return TRUE;
}

/*******************************************************************************
  * 函数名：Hardware_FlashWrite
  * 功  能：Flash写入数据
  * 参  数：void *Data：写入数据缓存地址
  *		   U32 u32WriteAddr：Flash写入地址
  *		   U32 u32WriteWordLen：写入字长度
  * 返回值：TRUE:成功  		FALSE:失败
  * 说  明：写入数据必须以字为单位，写入地址须为4的整数倍
*******************************************************************************/
Bool Hardware_FlashWrite(void *Data,U32 u32WriteAddr,U32 u32WriteWordLen)
{
	// 待写入字节数
	U32 u32WriteByteLen = u32WriteWordLen * 4;
	
	if((u32WriteAddr > ES8H0183_FLASH_START_ADDR + ES8H0183_FLASH_SIZE)
		|| u32WriteAddr & 0x00000003
		|| u32WriteByteLen <= 0
		|| u32WriteByteLen > ES8H0183_FLASH_SIZE)
	{
		// 写入地址或长度非法，返回失败
		return FALSE;
	}

    // Flash解锁
	Hardware_FlashUnlock();

	// 按字写入Flash
    for(U8 u8Index = 0; u8Index < u32WriteByteLen; u8Index += 4)
    {
        // 复位看门狗
        Hardware_RestartWDT();
        
		// 取小端字，同时避免Data不是四字节对齐导致读取内存崩溃
		U32 u32WordData = Get_LittleEndian_Value((U8*)((U32)Data+u8Index),4);

        // Flash写入Word
        if(ERROR == IAP_Code_WordProgram(u32WriteAddr,~u32WriteAddr, u32WordData))
        {
            // Flash加锁
            Hardware_FlashLock();

            // 返回结果
            return FALSE;
        }

        // 指向下一个字
		u32WriteAddr += 4;
    }

    // Flash加锁
    Hardware_FlashLock();

	// 返回结果
    return TRUE;
}
